import smtplib
import os
from typing import List, Optional, Dict, Any
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from email.header import Header
from email.utils import formataddr
from config import (
    smtp_configs,
    sender_email,
    sender_password,
    email_type,
    recipients,
    test_emails
)


class EmailSender:
    """邮件发送工具类"""

    def __init__(self,
                 smtp_server: str,
                 smtp_port: int,
                 sender_email: str,
                 sender_password: str,
                 sender_name: Optional[str] = None):
        """
        初始化邮件发送器

        :param smtp_server: SMTP服务器地址
        :param smtp_port: SMTP服务器端口
        :param sender_email: 发送者邮箱
        :param sender_password: 发送者邮箱密码或授权码
        :param sender_name: 发送者显示名称（可选）
        """
        self.smtp_server = smtp_server
        self.smtp_port = smtp_port
        self.sender_email = sender_email
        self.sender_password = sender_password
        self.sender_name = sender_name or sender_email.split('@')[0]  # 默认为邮箱前缀
        self.server: Optional[smtplib.SMTP] = None

    def _get_sender_addr(self) -> str:
        """格式化发送者地址（包含名称）"""
        return formataddr((self.sender_name, self.sender_email))

    def connect(self) -> bool:
        """连接到SMTP服务器，自动适配加密方式"""
        try:
            # 根据端口自动选择连接方式
            if self.smtp_port == 465:
                self.server = smtplib.SMTP_SSL(self.smtp_server, self.smtp_port)
            else:
                self.server = smtplib.SMTP(self.smtp_server, self.smtp_port)
                self.server.starttls()  # 对587端口使用STARTTLS

            # 登录邮箱
            self.server.login(self.sender_email, self.sender_password)
            print(f"✅ 成功连接到 {self.smtp_server}:{self.smtp_port}")
            return True
        except smtplib.SMTPException as e:
            print(f"❌ SMTP协议错误: {str(e)}")
        except Exception as e:
            print(f"❌ 连接服务器失败: {str(e)}")
        self.server = None
        return False

    def disconnect(self) -> None:
        """断开与SMTP服务器的连接"""
        if self.server:
            try:
                self.server.quit()  # 优雅关闭连接
                print("✅ 已断开与服务器的连接")
            except Exception as e:
                print(f"❌ 断开连接时出错: {str(e)}")
            finally:
                self.server = None

    def _validate_recipients(self, recipients: List[str]) -> bool:
        """验证收件人列表格式"""
        if not recipients or not isinstance(recipients, list):
            print("❌ 收件人列表不能为空且必须是列表类型")
            return False
        # 简单验证邮箱格式（包含@符号）
        invalid_emails = [email for email in recipients if '@' not in email]
        if invalid_emails:
            print(f"❌ 无效的邮箱地址: {', '.join(invalid_emails)}")
            return False
        return True

    def send_text_email(self,
                        recipients: List[str],
                        subject: str,
                        content: str) -> Dict[str, Any]:
        """
        发送纯文本邮件

        :return: 包含发送结果的字典，格式:
                 {
                     'success': bool,
                     'total': int,
                     'success_recipients': List[str],
                     'failed_recipients': List[str],
                     'error': Optional[str]
                 }
        """
        result = {
            'success': False,
            'total': len(recipients),
            'success_recipients': [],
            'failed_recipients': [],
            'error': None
        }

        if not self._validate_recipients(recipients):
            result['error'] = "收件人验证失败"
            return result

        try:
            # 确保已连接到服务器
            if not self.server and not self.connect():
                result['error'] = "无法连接到邮件服务器"
                return result

            # 创建邮件对象
            msg = MIMEText(content, 'plain', 'utf-8')
            msg['From'] = self._get_sender_addr()
            msg['To'] = ', '.join(recipients)
            msg['Subject'] = Header(subject, 'utf-8')

            # 发送邮件
            self.server.sendmail(self.sender_email, recipients, msg.as_string())
            result['success'] = True
            result['success_recipients'] = recipients.copy()
            print(f"✅ 文本邮件已成功发送到所有收件人: {', '.join(recipients)}")
        except smtplib.SMTPRecipientsRefused as e:
            # 处理收件人被拒绝的情况
            result['failed_recipients'] = list(e.recipients.keys())
            result['success_recipients'] = [r for r in recipients if r not in result['failed_recipients']]
            result['success'] = len(result['success_recipients']) > 0
            result['error'] = f"部分收件人被拒绝: {str(e)}"
            print(f"⚠️ 文本邮件部分发送失败 - 成功: {len(result['success_recipients'])}, 失败: {len(result['failed_recipients'])}")
            print(f"   失败收件人: {', '.join(result['failed_recipients'])}")
        except Exception as e:
            result['error'] = str(e)
            result['failed_recipients'] = recipients.copy()
            print(f"❌ 发送文本邮件失败: {str(e)}")

        return result

    def send_html_email(self,
                        recipients: List[str],
                        subject: str,
                        html_content: str) -> Dict[str, Any]:
        """
        发送HTML格式邮件

        :return: 包含发送结果的字典，格式同send_text_email
        """
        result = {
            'success': False,
            'total': len(recipients),
            'success_recipients': [],
            'failed_recipients': [],
            'error': None
        }

        if not self._validate_recipients(recipients):
            result['error'] = "收件人验证失败"
            return result

        try:
            if not self.server and not self.connect():
                result['error'] = "无法连接到邮件服务器"
                return result

            msg = MIMEText(html_content, 'html', 'utf-8')
            msg['From'] = self._get_sender_addr()
            msg['To'] = ', '.join(recipients)
            msg['Subject'] = Header(subject, 'utf-8')

            self.server.sendmail(self.sender_email, recipients, msg.as_string())
            result['success'] = True
            result['success_recipients'] = recipients.copy()
            print(f"✅ HTML邮件已成功发送到所有收件人: {', '.join(recipients)}")
        except smtplib.SMTPRecipientsRefused as e:
            result['failed_recipients'] = list(e.recipients.keys())
            result['success_recipients'] = [r for r in recipients if r not in result['failed_recipients']]
            result['success'] = len(result['success_recipients']) > 0
            result['error'] = f"部分收件人被拒绝: {str(e)}"
            print(f"⚠️ HTML邮件部分发送失败 - 成功: {len(result['success_recipients'])}, 失败: {len(result['failed_recipients'])}")
            print(f"   失败收件人: {', '.join(result['failed_recipients'])}")
        except Exception as e:
            result['error'] = str(e)
            result['failed_recipients'] = recipients.copy()
            print(f"❌ 发送HTML邮件失败: {str(e)}")

        return result

    def send_email_with_attachment(self,
                                   recipients: List[str],
                                   subject: str,
                                   content: str,
                                   attachments: Optional[List[str]] = None) -> Dict[str, Any]:
        """
        发送带附件的邮件

        :return: 包含发送结果的字典，格式同send_text_email
        """
        result = {
            'success': False,
            'total': len(recipients),
            'success_recipients': [],
            'failed_recipients': [],
            'error': None
        }

        if not self._validate_recipients(recipients):
            result['error'] = "收件人验证失败"
            return result

        try:
            if not self.server and not self.connect():
                result['error'] = "无法连接到邮件服务器"
                return result

            msg = MIMEMultipart()
            msg['From'] = self._get_sender_addr()
            msg['To'] = ', '.join(recipients)
            msg['Subject'] = Header(subject, 'utf-8')

            # 添加邮件正文
            msg.attach(MIMEText(content, 'plain', 'utf-8'))

            # 添加附件
            valid_attachments = []
            if attachments and isinstance(attachments, list):
                for file_path in attachments:
                    file_path = os.path.abspath(file_path)
                    if not os.path.isfile(file_path):
                        print(f"⚠️ 附件文件不存在 - {file_path}，已跳过")
                        continue
                    valid_attachments.append(file_path)

                    with open(file_path, 'rb') as f:
                        part = MIMEBase('application', 'octet-stream')
                        part.set_payload(f.read())

                    encoders.encode_base64(part)
                    filename = os.path.basename(file_path)
                    part.add_header(
                        'Content-Disposition',
                        f'attachment; filename*=UTF-8\'\'{filename}',  # 支持中文文件名
                    )

                    msg.attach(part)
                    print(f"📎 已添加附件: {filename}")

            if not valid_attachments and attachments:
                print("⚠️ 所有附件均无效，将发送无附件邮件")

            self.server.sendmail(self.sender_email, recipients, msg.as_string())
            result['success'] = True
            result['success_recipients'] = recipients.copy()
            print(f"✅ 带附件的邮件已成功发送到所有收件人: {', '.join(recipients)}")
        except smtplib.SMTPRecipientsRefused as e:
            result['failed_recipients'] = list(e.recipients.keys())
            result['success_recipients'] = [r for r in recipients if r not in result['failed_recipients']]
            result['success'] = len(result['success_recipients']) > 0
            result['error'] = f"部分收件人被拒绝: {str(e)}"
            print(f"⚠️ 带附件邮件部分发送失败 - 成功: {len(result['success_recipients'])}, 失败: {len(result['failed_recipients'])}")
            print(f"   失败收件人: {', '.join(result['failed_recipients'])}")
        except Exception as e:
            result['error'] = str(e)
            result['failed_recipients'] = recipients.copy()
            print(f"❌ 发送带附件的邮件失败: {str(e)}")

        return result

    def __enter__(self):
        """支持上下文管理器进入"""
        self.connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """支持上下文管理器退出（自动断开连接）"""
        self.disconnect()
        return False  # 不抑制异常


def main():
    """示例用法"""
    if email_type not in smtp_configs:
        print(f"❌ 不支持的邮箱类型: {email_type}")
        return

    # 从配置获取SMTP信息
    smtp_info = smtp_configs[email_type]

    # 使用上下文管理器自动管理连接
    with EmailSender(
            smtp_server=smtp_info["smtp_server"],
            smtp_port=smtp_info["smtp_port"],
            sender_email=sender_email,
            sender_password=sender_password,
            sender_name="测试邮件发送器"  # 可选：自定义发送者显示名称
    ) as sender:
        if not sender.server:  # 检查连接状态
            print("❌ 无法建立服务器连接，终止发送流程")
            return

        # 发送测试文本邮件
        print("\n----- 开始发送文本邮件 -----")
        text_result = sender.send_text_email(
            recipients,
            test_emails["text_email"]["subject"],
            test_emails["text_email"]["content"]
        )
        if text_result['success']:
            print(f"📊 文本邮件发送统计: 共 {text_result['total']} 个收件人，全部成功")
        else:
            print(
                f"📊 文本邮件发送统计: 共 {text_result['total']} 个收件人，成功 {len(text_result['success_recipients'])} 个，失败 {len(text_result['failed_recipients'])} 个")

        # 发送测试HTML邮件
        print("\n----- 开始发送HTML邮件 -----")
        html_result = sender.send_html_email(
            recipients,
            test_emails["html_email"]["subject"],
            test_emails["html_email"]["content"]
        )
        if html_result['success']:
            print(f"📊 HTML邮件发送统计: 共 {html_result['total']} 个收件人，全部成功")
        else:
            print(
                f"📊 HTML邮件发送统计: 共 {html_result['total']} 个收件人，成功 {len(html_result['success_recipients'])} 个，失败 {len(html_result['failed_recipients'])} 个")

        # 发送测试带附件的邮件
        print("\n----- 开始发送带附件邮件 -----")
        attachment_result = sender.send_email_with_attachment(
            recipients,
            test_emails["attachment_email"]["subject"],
            test_emails["attachment_email"]["content"],
            test_emails["attachment_email"]["attachments"]
        )
        if attachment_result['success']:
            print(f"📊 带附件邮件发送统计: 共 {attachment_result['total']} 个收件人，全部成功")
        else:
            print(
                f"📊 带附件邮件发送统计: 共 {attachment_result['total']} 个收件人，成功 {len(attachment_result['success_recipients'])} 个，失败 {len(attachment_result['failed_recipients'])} 个")


if __name__ == "__main__":
    main()